#include "buffer.h"
#include <bits/types/struct_iovec.h>
#include <cassert>
#include <cstddef>
#include <sys/types.h>

Buffer::Buffer(int initBuffSize) : 
buffer_(initBuffSize), writePos_(0), readPos_(0){}

size_t Buffer::ReadableBytes() const {
    return writePos_ - readPos_;
}

size_t Buffer::WritableBytes() const {
    return buffer_.size() - writePos_;
}

size_t Buffer::PrependableBytes() const {
    return readPos_;
}

const char* Buffer::Peek() const {
    return BeginPtr_() + readPos_;
}

// 为什么只是直接移动读指针？而没有实际读入数据？
void Buffer::Retrieve(size_t len) {
    assert(len <= ReadableBytes()); // 断言的使用
    readPos_ += len;
}

// 这个函数的实现也不是很理解
void Buffer::RetrieveUntil(const char* end) {
    assert(Peek() <= end);
    Retrieve(end - Peek());
}

void Buffer::RetrieveAll() {
    // bzero(&buffer_[0], buffer_.size());
    /*
      原版使用的是上面的注释部分
      但是这部分GPT说已经不建议使用了
      因为不符合C语言的编写标准
    */
    memset(&buffer_[0], 0, buffer_.size());

    readPos_ = 0;
    writePos_ = 0;
}

std::string Buffer::RetrieveAllToStr() {
    std::string str(Peek(), ReadableBytes());
    RetrieveAll();
    return str;
}

/*
    以下两个函数被设计的一模一样
    但是我不理解其中的含义
*/
const char* Buffer::BeginWriteConst() const {
    return BeginPtr_() + writePos_;
}
char* Buffer::BeginWrite() {
    return BeginPtr_() + writePos_;
}

void Buffer::HasWritten(size_t len) {
    writePos_ += len;
}

void Buffer::Append(const std::string& str) {
    Append(str.data(), str.size());
}

void Buffer::Append(const void* data, size_t len) {
    assert(data); // data不能是空指针
    Append(static_cast<const char*>(data), len);
}

void Buffer::Append(const char* str, size_t len) {
    assert(str);
    EnsureWriteable(len);
    std::copy(str, str+len, BeginWrite());
    HasWritten(len);
}

void Buffer::Append(const Buffer& buff) {
    Append(buff.Peek(), buff.ReadableBytes());
}

void Buffer::EnsureWriteable(size_t len) {
    if(WritableBytes() < len) {
        MakeSpace_(len);
    }

    // 防止扩容失败
    assert(WritableBytes() >= len);
}

ssize_t Buffer::ReadFD(int fd, int *saveErrno) {
    // 65536是缓冲区的常见大小
    char buff[65536];
    struct iovec iov[2];
    const size_t writable = WritableBytes();

    iov[0].iov_base = BeginPtr_() + writePos_;
    iov[0].iov_len = writable;
    // 备用缓冲区
    iov[1].iov_base = buff;
    iov[1].iov_len = sizeof(buff);

    /*
        将fd中的内容分散读入缓冲区（在第一个缓冲区大小不满足要求的时候发生）
        
        假如：fd中有150字节的数据
        iov[0].iov_len == iov[1].iov_len == 100;
        那么iov[0]中会读入100字节，剩余的50字节读入iov[1]中
    */
    const ssize_t len = readv(fd, iov, 2);
    // readv读取出错
    if(len < 0) {
        *saveErrno = errno;
    }
    // buffer_能够读完fd中的内容
    else if(static_cast<size_t>(len) <= writable) {
        writePos_ += len;
    }
    // 需要启用额外缓冲区
    else {
        writePos_ = buffer_.size();
        Append(buff, len-writable);
    }
    return len;
}

ssize_t Buffer::WriteFD(int fd, int *saveErrno) {
    size_t readSize = ReadableBytes();
    ssize_t len = write(fd, Peek(), readSize);
    if(len < 0) {
        *saveErrno = errno;
    }
    else {
        readPos_ += len;
    }
    return len;
}

char* Buffer::BeginPtr_() {
    return &*buffer_.begin();
}

const char* Buffer::BeginPtr_() const {
    return &*buffer_.begin();
}

void Buffer::MakeSpace_(size_t len) {
    if(WritableBytes() + PrependableBytes() < len) {
        buffer_.resize(writePos_ + len + 1);
    }
    else {
        size_t readable = ReadableBytes();
        std::copy(BeginPtr_() + readPos_, BeginPtr_() + writePos_, BeginPtr_());
        readPos_ = 0;
        writePos_ = readPos_ + readable;
        assert(readable == ReadableBytes());
    }
}